﻿using System;
using System.Collections.Generic;
using System.IO;
using Android.App;
using Android.Content;
using Android.Content.PM;
using Android.Graphics;
using Android.Graphics.Drawables;
using Android.Media;
using Android.OS;
using Android.Runtime;
using Android.Support.Constraints;
using Android.Support.Design.Widget;
using Android.Support.V4.App;
using Android.Support.V4.Content;
using Android.Support.V4.View;
using Android.Support.V7.App;
using Android.Support.V7.Widget;
using Android.Util;
using Android.Views;
using Android.Widget;
using Java.Lang;
using static Android.Media.MediaPlayer;
using static Android.Support.Design.Widget.TabLayout;
using Fragment = Android.Support.V4.App.Fragment;
using System.Security.Cryptography;
using System.Threading.Tasks;
using Plugin.Permissions;
using Plugin.Permissions.Abstractions;
using Permission = Plugin.Permissions.Abstractions.Permission;

namespace mb.Droid
{
    public class MySquareLayout : FrameLayout
    {
        public float aspect;
        public MySquareLayout(Context context, float aspect) : base(context)
        {
            this.aspect = aspect;
        }

        protected override void OnMeasure(int widthMeasureSpec, int heightMeasureSpec)
        {
            var wm = MeasureSpec.GetMode(widthMeasureSpec);
            var ws = MeasureSpec.GetSize(widthMeasureSpec);
            var hm = MeasureSpec.GetMode(heightMeasureSpec);
            var hs = MeasureSpec.GetSize(heightMeasureSpec);

            //ILog logger = ServiceLocator.Instance.Get<ILog>();
            // logger.Log("grid measure", ws, hs);

            base.OnMeasure(widthMeasureSpec, MeasureSpec.MakeMeasureSpec((int) (ws * aspect), hm));
        }
    }

    public class MyFragment : Android.Support.V4.App.Fragment
    {
        static ILog logger = ServiceLocator.Instance.Get<ILog>();
        public int Hold;
        public string Title;

        public Dictionary<string, object> dict = new Dictionary<string, object>();
        public object data;

        public Func<MyFragment, ViewGroup, View> MyOnCreateView;
        public Action<MyFragment, View, Bundle> MyOnViewCreated;
        public Action<MyFragment> MyOnPause;
        public Action<MyFragment> MyOnResume;
        public Action<MyFragment> MyOnDestroyView;
        public Action<MyFragment> MyOnDestroy;
        public Action<MyFragment> MyOnDetach;
        public Action<MyFragment, bool> MyOnVisibleHint;
        public Action<MyFragment, Context> MyOnAttach;
        public Action<MyFragment, Fragment> MyOnAttachFragment;

        public Action<MyFragment> MyOnReEnter;

        public override bool UserVisibleHint
        {
            get { return base.UserVisibleHint; }
            set
            {
                base.UserVisibleHint = value;
                MyOnVisibleHint?.Invoke(this, value);
            }
        }
        public T GetUserData<T>(string key)
        {
            object obj;
            dict.TryGetValue(key, out obj);
            if (obj == null) return default(T);
            return (T) obj;
        }

        public override void OnPause()
        {
            base.OnPause();
            MyOnPause?.Invoke(this);

        }
        public override void OnResume()
        {
            base.OnResume();
            MyOnResume?.Invoke(this);
        }
        public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
        {
            // logger.Log("call OnView->", OnView);
            return MyOnCreateView(this, container);
        }
        public override void OnViewCreated(View view, Bundle savedInstanceState)
        {
            base.OnViewCreated(view, savedInstanceState);
            MyOnViewCreated?.Invoke(this, view, savedInstanceState);
        }

        public override void OnDestroy()
        {
            base.OnDestroy();
            MyOnDestroy?.Invoke(this);

        }
        public override void OnDestroyView()
        {
            base.OnDestroyView();
            MyOnDestroyView?.Invoke(this);

        }
        public override void OnDetach()
        {
            base.OnDetach();
            MyOnDetach?.Invoke(this);
        }

        public override void OnAttach(Context context)
        {
            base.OnAttach(context);
            MyOnAttach?.Invoke(this, context);
        }
        public override void OnAttachFragment(Fragment fragment)
        {
            base.OnAttachFragment(fragment);
            MyOnAttachFragment?.Invoke(this, fragment);
        }
    }

    public class MySimplePagerAdapter : PagerAdapter
    {
        public List<View> Views;

        public override int Count => Views.Count;

        public override Java.Lang.Object InstantiateItem(ViewGroup collection, int position)
        {
            // CustomPagerEnum customPagerEnum = CustomPagerEnum.values() [position];
            // LayoutInflater inflater = LayoutInflater.from(mContext);
            // ViewGroup layout = (ViewGroup) inflater.inflate(customPagerEnum.getLayoutResId(), collection, false);
            // collection.addView(layout);
            // return layout;
            var v = Views.ToArray() [position];
            collection.AddView(v);
            return v;
        }

        public override void DestroyItem(ViewGroup collection, int position, Java.Lang.Object @view)
        {
            collection.RemoveView((View) view);
        }

        public override bool IsViewFromObject(View view, Java.Lang.Object @obj)
        {
            return view == obj;
        }

        // public override string GetPageTitle(int position)
        // {
        //     CustomPagerEnum customPagerEnum = CustomPagerEnum.values() [position];
        //     return mContext.getString(customPagerEnum.getTitleResId());
        // }
    }

    public class MyPagerAdapter : FragmentStatePagerAdapter
    {
        public List<MyFragment> fragments;

        public override int Count => fragments.Count;

        public MyPagerAdapter(Context context, Android.Support.V4.App.FragmentManager fm) : base(fm) { }

        public override int GetItemPosition(Java.Lang.Object frag) => PositionNone;
        public override Java.Lang.ICharSequence GetPageTitleFormatted(int position) =>
            new Java.Lang.String(fragments.ToArray() [position].Title);

        public override Android.Support.V4.App.Fragment GetItem(int position)
        {
            return fragments.ToArray() [position];
        }

    }

    public class MyGlobalLayoutListener : Java.Lang.Object, ViewTreeObserver.IOnGlobalLayoutListener
    {
        public Action OnGlobalLayout_CS;
        public void OnGlobalLayout()
        {
            OnGlobalLayout_CS();
        }
    }

    public class MyMediaPlayerListener : Java.Lang.Object, IOnPreparedListener, IOnErrorListener, IOnBufferingUpdateListener, IOnCompletionListener
    {
        public int Nothing;
        public Action<MediaPlayer> OnPrepared_CS;
        public Action<MediaPlayer, MediaError, int> OnError_CS;
        public Action<MediaPlayer, float> OnBufferingUpdate_CS;
        public Action<MediaPlayer> OnCompletion_CS;

        public void OnBufferingUpdate(MediaPlayer mp, int percent)
        {
            OnBufferingUpdate_CS?.Invoke(mp, percent);
        }

        public void OnCompletion(MediaPlayer mp)
        {
            OnCompletion_CS?.Invoke(mp);
        }

        public bool OnError(MediaPlayer mp, [GeneratedEnum] MediaError what, int extra)
        {
            OnError_CS?.Invoke(mp, what, extra);
            return true;
        }

        public void OnPrepared(MediaPlayer mp)
        {
            OnPrepared_CS?.Invoke(mp);
        }
    }

    public class MySurfaceHolderCallback : Java.Lang.Object, ISurfaceHolderCallback
    {
        public Action<ISurfaceHolder, Format, int, int> OnSurfaceChanged;
        public Action<ISurfaceHolder> OnSurfaceCreated;
        public Action<ISurfaceHolder> OnSurfaceDestroyed;

        public void SurfaceChanged(ISurfaceHolder holder, [GeneratedEnum] Format format, int width, int height)
        {
            OnSurfaceChanged?.Invoke(holder, format, width, height);
        }

        public void SurfaceCreated(ISurfaceHolder holder)
        {
            OnSurfaceCreated?.Invoke(holder);
        }

        public void SurfaceDestroyed(ISurfaceHolder holder)
        {
            OnSurfaceDestroyed?.Invoke(holder);
        }
    }

    public class MyDialogFragment : Android.Support.V4.App.DialogFragment
    {
        public Func<MyDialogFragment, ViewGroup, View> MyOnCreateView;
        public Action<MyDialogFragment, Bundle> MyOnCreate;
        public Action<MyDialogFragment> MyOnStart;
        public Action<MyDialogFragment> MyOnResume;
        public Action<MyDialogFragment, View, Bundle> MyOnViewCreated;

        public MyDialogFragment() : base() { }
        public override void OnCreate(Bundle savedInstanceState)
        {
            base.OnCreate(savedInstanceState);
            MyOnCreate?.Invoke(this, savedInstanceState);
        }
        public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
        {
            return MyOnCreateView(this, container);
        }
        public override void OnViewCreated(View view, Bundle savedInstanceState)
        {
            base.OnViewCreated(view, savedInstanceState);
            MyOnViewCreated?.Invoke(this, view, savedInstanceState);
        }

        public override void OnResume()
        {
            base.OnResume();
            MyOnResume?.Invoke(this);
        }
        public override void OnStart()
        {
            base.OnStart();
            MyOnStart?.Invoke(this);
        }

        public override void OnStop()
        {
            base.OnStop();
        }

    }

    public class MyTouchListener : Java.Lang.Object, View.IOnTouchListener
    {
        public Func<View, MotionEvent, bool> MyOnTouch;
        public bool OnTouch(View v, MotionEvent e)
        {
            return MyOnTouch(v, e);
        }
    }

    public class SimpleDialogFragment : Android.Support.V4.App.DialogFragment
    {
        View contentView;
        bool cancelOnClickOut;
        public bool Transparent;
        public SimpleDialogFragment(View view, bool cancelOnClickOut)
        {
            this.contentView = view;
            this.cancelOnClickOut = cancelOnClickOut;
        }

        public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
        {
            Dialog.SetCanceledOnTouchOutside(cancelOnClickOut);
            Dialog.Window.SetBackgroundDrawable(new ColorDrawable(Color.Transparent));
            Cancelable = cancelOnClickOut;
            return contentView;
        }

        public override void OnResume()
        {
            base.OnResume();
            Window window = Dialog.Window;
            Point size = new Point();

            Display display = window.WindowManager.DefaultDisplay;
            display.GetSize(size);

            int width = size.X;
            // window.SetLayout((int) (width * 0.90), WindowManagerLayoutParams.WrapContent);
        }
    }
    public static class Util
    {
        public static async Task<bool> HasPermission(Permission permNeed)
        {
            // var permNeed = Permission.Contacts;
            var status = await CrossPermissions.Current.CheckPermissionStatusAsync(permNeed);
            if (status != PermissionStatus.Granted)
            {
                if (await CrossPermissions.Current.ShouldShowRequestPermissionRationaleAsync(permNeed))
                {
                    // await DisplayAlert("Need location", "Gunna need that location", "OK");
                }

                var results = await CrossPermissions.Current.RequestPermissionsAsync(permNeed);
                if (results.ContainsKey(Permission.Location))
                    status = results[Permission.Location];
            }

            if (status != PermissionStatus.Granted)
                return false;

            return true;
        }

        public static string GetSecureId()
        {
            return Android.Provider.Settings.Secure.GetString(Android.App.Application.Context.ContentResolver, Android.Provider.Settings.Secure.AndroidId);
        }
        public static RelativeLayout.LayoutParams AddRuleEx(this RelativeLayout.LayoutParams lp, LayoutRules rule, int id = -1)
        {
            if (id == -1)
                lp.AddRule(rule);
            else
                lp.AddRule(rule, id);
            return lp;
        }
        public static Point GetWindowSize()
        {
            var ctx = StartActivity.This;
            Point size = new Point();
            Display display = ctx.WindowManager.DefaultDisplay;
            display.GetSize(size);
            return size;
        }
        public static bool isEmulator()
        {
            return Build.Fingerprint.StartsWith("generic") ||
                Build.Fingerprint.StartsWith("unknown") ||
                Build.Model.Contains("google_sdk") ||
                Build.Model.Contains("Emulator") ||
                Build.Model.Contains("Android SDK built for x86") ||
                Build.Manufacturer.Contains("Genymotion") ||
                (Build.Brand.StartsWith("generic") && Build.Device.StartsWith("generic")) ||
                "google_sdk".Equals(Build.Product);
        }

        public static void SetCursorColor(EditText view, Color color)
        {
            try
            {
                var jclass = Java.Lang.Class.FromType(typeof(TextView));
                var fRes = jclass.GetDeclaredField("mCursorDrawableRes");
                fRes.Accessible = true;
                int drawableResId = fRes.GetInt(view);

                // Get the drawable and set a color filter
                Drawable drawable = ContextCompat.GetDrawable(view.Context, drawableResId);
                drawable.SetColorFilter(color, PorterDuff.Mode.SrcIn);
                Drawable[] drawables = { drawable, drawable };

                // Get the editor
                var fEditor = jclass.GetDeclaredField("mEditor");
                fEditor.Accessible = true;
                var editor = fEditor.Get(view);

                // Set the drawables
                var fDrawable = editor.Class.GetDeclaredField("mCursorDrawable");
                fDrawable.Accessible = true;
                fDrawable.Set(editor, drawables);
            }
            catch (System.Exception e)
            {
                App.logger.Log("setcursorcolor fail", e.ToString());
            }
        }

        public static void ShowPopView(View view, bool cancelOnClickOut = true)
        {
            var ctx = StartActivity.This;
            var dialogFragment = new SimpleDialogFragment(view, cancelOnClickOut);
            dialogFragment.Show(ctx.SupportFragmentManager, "pop");
        }

        public static void ShowMsgBox(string msg, Action onClick = null)
        {
            var Context = StartActivity.This;
            var ws = Util.GetWindowSize();
            int width = (int) (ws.X * 0.7f);

            var root = new LinearLayout(Context)
            {
                Orientation = Android.Widget.Orientation.Vertical,
                // Background = new ColorDrawable(Color.Blue),
            };
            root.Click += delegate { onClick?.Invoke(); };

            var tv = new TextView(Context)
            {
                Text = msg,
                TextSize = 20,
                // Background = new ColorDrawable(Color.Red),
            };
            root.AddView(tv, new LinearLayout.LayoutParams(-2, -2)
            {
                // LeftMargin = 20,
                // RightMargin = 20,
                Gravity = GravityFlags.Center,
            });
            root.SetGravity(GravityFlags.Center);

            //对于dialogfragment来说，container view自身的layoutparam似乎没用，必须显式设置其子节点大小来保证对话框大小
            var container = new LinearLayout(Context);
            container.AddView(root, new LinearLayout.LayoutParams(width, width));
            container.SetBackgroundColor(Color.White);
            Util.ShowPopView(container, false);
        }
    }
}
namespace mb
{
    public static partial class Util
    {
        public static string ReadBuiltinFile(string path)
        {
            string content = null;
            try
            {
                var assets = mb.Droid.StartActivity.This.Assets;
                using(StreamReader sr = new StreamReader(assets.Open(path)))
                {
                    content = sr.ReadToEnd();
                }
                return content;
            }
            catch (System.Exception)
            {
                App.logger.Log("ReadBuiltinFile fail", path);
                return content;
            }
        }
    }
}